﻿using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Collections;
using System.Net.NetworkInformation;

namespace MassReboot
{
    public partial class Form1 : Form
    {
        public static object UpdateLock = new object();

        public Form1()
        {
            InitializeComponent();
            passwordTB.TextBox.UseSystemPasswordChar = true;
        }

        private void AddItem()
        {
            if (string.IsNullOrEmpty(textBox1.Text))
                MessageBox.Show("Please enter a value");
            else
                listView.Items.Add(new ListViewItem(textBox1.Text.ToUpper()));
            textBox1.Clear();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            AddItem();
        }

        private void AddListItem(string name, string status, string message, Color backColor)
        {

            if (!string.IsNullOrEmpty(name))
            {
                var selItem = from ListViewItem s in listView.Items where s.Text.Equals(name, StringComparison.CurrentCultureIgnoreCase) select s;

                if (selItem.Count() > 0)
                {
                    ListViewItem[] foundItems = selItem.ToArray();
                    for (int i = 0; i < foundItems.Count(); i++)
                    {
                        listView.Items.Remove(foundItems[i]);
                    }
                }
                ListViewItem item = new ListViewItem(new string[] { name.ToUpper().Trim(), status, message });
                item.BackColor = backColor;
                listView.Items.Add(item);
            }
        }

        private void ImportSystems()
        {
            DialogResult result = openFileDialog1.ShowDialog(this);
            int importCount = 0;
            if (DialogResult.OK == result)
            {
                listView.Items.Clear();
                using (StreamReader reader = File.OpenText(openFileDialog1.FileName))
                {
                    string input = null;
                    while ((input = reader.ReadLine()) != null)
                    {
                        AddListItem(input, "", "", Color.White);
                        importCount += 1;
                    }
                }
            }
            ToConsole("Imported " + importCount + " from " + openFileDialog1.FileName);
        }

        private void ToConsole(string text)
        {
            string temp = textBox2.Text;
            textBox2.Text = DateTime.Now.ToString() + ": " + text + "\r\n" + temp;
            textBox2.ScrollToCaret();
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            ImportSystems();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show(this, "Are you sure you want reboot the listed " + listView.Items.Count + " computer(s)?", "Reboot Systems", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                RebootItems(listView.Items.GetEnumerator());
            }
        }

        private void AttachMonitor(ComputerEventArgs e)
        {
            //Wait for system to go offline
            using (Ping ping = new Ping())
            {
                try
                {
                    while (ping.Send(e.Items[(int)ComputerEnum.Name]).Status == IPStatus.Success)
                    {
                        Thread.Sleep(5000);
                        Monitor.TryEnter(UpdateLock, TimeSpan.FromSeconds(30));
                        UpdateInvoke(new ComputerEventArgs("Waiting for " + e.Items[(int)ComputerEnum.Name] + " to go offline.",
                            new string[] { e.Items[(int)ComputerEnum.Name], e.Items[(int)ComputerEnum.IP], "Shutting Down System" }, ItemStatus.Good));
                        Monitor.Exit(UpdateLock);
                    }
                }
                catch (Exception ex)
                {

                }
                finally
                {
                    try
                    {
                        Monitor.Exit(UpdateLock);
                    }
                    catch (Exception ex1) { }
                }
                try
                {
                    while (ping.Send(e.Items[(int)ComputerEnum.Name]).Status != IPStatus.Success)
                    {
                        Thread.Sleep(5000);
                        Monitor.TryEnter(UpdateLock, TimeSpan.FromSeconds(30));
                        UpdateInvoke(new ComputerEventArgs("Waiting for " + e.Items[(int)ComputerEnum.Name] + " to come online.",
                                new string[] { e.Items[(int)ComputerEnum.Name], e.Items[(int)ComputerEnum.IP], "Booting System" }, ItemStatus.Good));
                        Monitor.Exit(UpdateLock);
                    }
                }
                catch (Exception ex2)
                {

                }
                finally
                {
                    try
                    {
                        Monitor.Exit(UpdateLock);
                    }
                    catch (Exception ex3) { }

                }
            }
            UpdateInvoke(new ComputerEventArgs("Rebooted " + e.Items[(int)ComputerEnum.Name] + " succesfully.",
                                   new string[] { e.Items[(int)ComputerEnum.Name], e.Items[(int)ComputerEnum.IP], "Completed" }, ItemStatus.Completed));


        }

        private void UpdateView(ComputerEventArgs e)
        {
            try
            {
                Color itemColor = new Color();
                switch (e.Status)
                {
                    case ItemStatus.Completed:
                        itemColor = Color.LightGreen;
                        break;
                    case ItemStatus.Error:
                        itemColor = Color.Red;
                        break;
                    case ItemStatus.Good:
                        itemColor = Color.Yellow;
                        break;
                    default:
                        itemColor = Color.White;
                        break;
                }

                ToConsole(e.Response);

                AddListItem(e.Items[(int)ComputerEnum.Name], e.Items[(int)ComputerEnum.IP], e.Items[(int)ComputerEnum.Message], itemColor);
                listView.Update();
            }
            catch (Exception ex)
            {
                ToConsole(ex.Message);
            }
        }

        private void UpdateInvoke(ComputerEventArgs e)
        {
            if (this.InvokeRequired)
            {
                // Reinvoke the same method if necessary        
                BeginInvoke(new MethodInvoker(delegate() { UpdateView(e); }));
            }
            else
            {
                UpdateView(e);
            }
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Are you sure?", "Message", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            switch (result)
            {
                case DialogResult.Yes:
                {
                    listView.Items.Clear();
                    break;
                }
                case DialogResult.No:
                {
                    break;
                }
                case DialogResult.Cancel:
                {
                    break;
                }
            }
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                AddItem();
                e.SuppressKeyPress = true;
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = saveFileDialog1.ShowDialog(this);
            int writeCount = 0;
            if (DialogResult.OK == result)
            {
                if (!File.Exists(saveFileDialog1.FileName)) File.Create(saveFileDialog1.FileName);
                using (StreamWriter writer = new StreamWriter(saveFileDialog1.FileName))
                {
                    foreach (ListViewItem item in listView.Items)
                    {
                        writer.WriteLine(item.Text);
                        writeCount += 1;
                    }
                }
            }
            ToConsole("Saved " + writeCount + " items to " + saveFileDialog1.FileName);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ImportSystems();
        }

        private void listView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
            {
                DeleteSelectedItems();
                listView.Update();
                e.SuppressKeyPress = true;
            }
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DeleteSelectedItems();
            listView.Update();
        }

        private void DeleteSelectedItems()
        {
            foreach (ListViewItem item in listView.SelectedItems)
            {
                ToConsole("Removing " + item.Text + " from list.");
                item.Remove();
            }
        }

        private void RebootItems(IEnumerator items)
        {
            ToConsole("Starting Engine!");
            IEnumerator enumerator = items;

            while (enumerator.MoveNext())
            {
                if (enumerator.Current == null) break;
                ThreadPool.QueueUserWorkItem(o =>
                {
                    Computer comp;
                    if (toolStripButton4.Checked)
                        comp = new Computer((ListViewItem)o, checkBox1.Checked, usernameTB.Text, passwordTB.Text);
                    else
                        comp = new Computer((ListViewItem)o, checkBox1.Checked, null, null);

                    comp.ComputerErrorTriggered += new EventHandler<ComputerEventArgs>((i1, evt1) =>
                    {
                        try
                        {
                            while (!Monitor.TryEnter(UpdateLock)) { }
                            UpdateInvoke(evt1);
                        }
                        finally
                        {
                            Monitor.Exit(UpdateLock);
                        }
                    });
                    comp.RestartStarted += new EventHandler<ComputerEventArgs>((i2, evt2) =>
                    {
                        try
                        {
                            while (!Monitor.TryEnter(UpdateLock)) { }
                            UpdateInvoke(evt2);
                            //Attach monitor worker item
                            ThreadPool.QueueUserWorkItem(o1 => AttachMonitor(evt2));
                        }
                        finally
                        {
                            Monitor.Exit(UpdateLock);

                        }
                    });
                    comp.BeginRestart();
                }, enumerator.Current);
            }
        }

        private void RebootComputerToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            RebootItems(listView.SelectedItems.GetEnumerator());
        }
        private void toolStripButton4_Click(object sender, EventArgs e)
        {

        }
    }
}
